#include "cmdParser.h"
#include "utils.h"
#define BLOCK_SIZE (8 * 1024)

/*
 *description:
 *       判断是否为支持的命令类型，若是返回true,否则返回false
 *usage:
 *       char *cmd = "ls";
 *       CMD_TYPE type;
 *       bool isValid = isValidCmd(cmd, &type);
 *       // isValid == true;
 *       // type == LS;
 *paras:
 *       cmd         命令名称, 如：cd, ls, pwd
 *       type        枚举命令类型值指针，用于接收命令类型枚举值
 *returns:
 *       true        支持的有效命令
 *       false       不支持的无效命令
 */
static bool isValidCmd(const char *cmd, CMD_TYPE *type);

// 判断某个文件在某个路径下是否存在重名，mkdir,cd私用函数
bool isExist(char *path, char *file_name) // 张
{
    DIR *dirp = opendir(path);
    ERROR_CHECK(dirp, NULL, "opendir");
    struct dirent *pdirent;
    while ((pdirent = readdir(dirp)) != NULL)
    {
        if (strcmp(file_name, pdirent->d_name) == 0)
        {
            closedir(dirp);
            return true;
        }
    }
    closedir(dirp);
    return false;
}
// cd命令处理【0：失败，1：进入成功；2：当前路径(cd .)；3：退回(cd ..)；4：进入根目录(cd /)】
void cdFunc(splictDataCarrier_st *splictDataCarrier, char **tokens, char *cur, char *clientCur, int net_fd, int len) // 旭
{

    // 判断cd后没有参数的情况
    if (len <= 1 || strcmp(tokens[0], "cd") != 0)
    {
        int flag = 0;
        // 命令结果标志位，如果结果为0，cd处理命令错误，不需要修改客户端当前工作路径
        // 结果为1正确，需要修改客户端当前工作路径
        send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
    }

    // cd .的情况【返回2】
    if (len == 2 && strcmp(tokens[1], ".") == 0)
    {
        int flag = 2;
        send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
        return;
    }

    // cd ..的情况【返回3】
    if (len == 2 && strcmp(tokens[1], "..") == 0)
    {
        int flag = 3;
        send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
        return;
    }

    // for (int i = 0; i < len; i++)
    // {
    //     printf("////74:token[%d]:%s\n", i, tokens[i]);
    // }
    // 判断命令格式是否正确
    char absPath[256] = {0};
    bool isExistPath = getServerAbsPath(splictDataCarrier, absPath);
    if (isExistPath == true)
    {
        // printf("文件存在\n");
        int flag = 1;
        // 文件存在
        send(splictDataCarrier->socketFd, &flag, sizeof(int), 0);
        // printf("flag:%d\n", flag);
        return;
    }
    else
    {
        // 文件不存在
        printf("文件不存在\n");
        int flag = 0;
        send(net_fd, &flag, 4, 0);
        return;
    }

    int size;
    char **tokens2 = splitString(splictDataCarrier->command, " ", &size);
    if (tokens2[1][0] == '/')
    {
        int flag = 4;
        send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
    }
    // 当前服务器端的初始绝对路径
    // char path[256] = {0};
    // memset(path, 0, sizeof(path));
    // printf("81:cur:%s\n",cur);
    // strcpy(path, cur);

    // int num = 1; // tokens下标
    // while (num < len)
    // {
    //     bool exist = isExist(path, tokens[num]);
    //     if (exist == true)
    //     {
    //         // 修改path服务器端的路径,不可以修改clientCur路径，最后全部正确才可以更改
    //         strcat(path, "/");
    //         strcat(path, tokens[num]);
    //         num++;
    //         continue;
    //     }

    //     // 走到这里，说明当前目录没有对应文件夹，cd失败
    //     // 命令结果标志位，如果结果为0，cd处理命令错误，不需要修改客户端当前工作路径
    //     // 结果为1正确，需要修改客户端当前工作路径
    //     int flag = 0;
    //     int ret = send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
    //     ERROR_CHECK(ret, -1, "send");
    //     return;
    // }
    // 确定cd命令正确后，修改当前客户端绝对路径
    // num = 1;
    // int isRoot = 0;
    // if (strlen(clientCur) == 1)
    // {
    //     isRoot = 1;
    // }
    // while (num < len)
    // {
    //     if (num == 1 && isRoot == 1)
    //     {
    //         strcat(clientCur, tokens[num++]);
    //         continue;
    //     }
    //     strcat(clientCur, "/");
    //     strcat(clientCur, tokens[num++]);
    // }
    // // cd命令正确，发送信息
    // // 命令结果标志位，如果结果为0，cd处理命令错误，不需要修改客户端当前工作路径
    // // 结果为1正确，需要修改客户端当前工作路径
    // flag = 1;
    // int ret = send(net_fd, &flag, sizeof(int), 0);
    // ERROR_CHECK(ret, -1, "send");
    // int len1 = strlen(clientCur);
    // ret = send(net_fd, &len1, sizeof(int), 0);
    // ERROR_CHECK(ret, -1, "send");
    // ret = send(net_fd, clientCur, len1, 0);
    // ERROR_CHECK(ret, -1, "send");
}

// note: 经过测试，该实现无法列出部分文件，如client.c预计是由于权限问题，后续解决
// zs 2024.07.08
// lsReturn_t lsCmdSimulation(const char *curPath, const char *path)
lsReturn_t lsCmdSimulation(splictDataCarrier_st *splictDataCarrier)
{

    // printf("进入lsCmdSimulation---------->\n");
    // printf("传入split参数: %p\n", splictDataCarrier);
    lsReturn_t ret;
    memset((void *)&ret, 0, sizeof(ret));
    ret.exec_status = false;

    // 目的路径，需要一个处理函数
    char destPath[256] = {'\0'};
    bool isValid = getServerAbsPath(splictDataCarrier, destPath);

    // printf("-----------------------------\n");
    // printf("服务器获取到的绝对路径: %s\n", destPath);
    // printf("-----------------------------\n");
    /*-----------测试数据-----------*/
    // char *destPath = "/home/tsang/srcode/group_project/client";
    // char *destPath = "/home/tsang/srcode/group_project";
    /*-----------测试数据-----------*/

    if (!isValid)
    {
        // sprintf(ret.description, "目录: %s不存在！", destPath);
        return ret;
    }

    struct dirent *entry;
    struct stat fileStat;
    DIR *dp = opendir(destPath);

    if (dp == NULL)
    {
        perror("opendir");
        // sprintf(ret.description, "打开目录: %s失败！:%s", destPath, strerror(errno));
        return ret;
    }

    // 存放destPath目录下的所有文件、子目录信息
    fileinfo_t *fileinfoArray = (fileinfo_t *)calloc(1, sizeof(fileinfo_t));
    // fileinfo_t *fileinfoArray = NULL;
    ret.filedirs.size = 0;
    while ((entry = readdir(dp)) != NULL)
    {
        char fullPath[1024];
        snprintf(fullPath, sizeof(fullPath), "%s/%s", destPath, entry->d_name);
        // printf("-----------------------------\n");
        // printf("Full path: %s\n", fullPath);
        // printf("-----------------------------\n");
        if (stat(fullPath, &fileStat) == -1)
        {
            perror("stat");
            continue;
        }
        /*
                printf("Name: %s\n", entry->d_name);
                printf("Type: %s\n", (S_ISDIR(fileStat.st_mode)) ? "Directory" : "File");
                printf("Size: %ld bytes\n", fileStat.st_size);
                printf("Permissions: %o\n", fileStat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
                printf("Last Modified: %s\n", ctime(&fileStat.st_mtime));
                printf("\n");
        */
        // 动态分配存储单个文件、目录信息内存
        fileinfo_t *fileinfoPtr = (fileinfo_t *)calloc(1, sizeof(*fileinfoPtr));
        strcpy(fileinfoPtr->file_name, entry->d_name);
        fileinfoPtr->file_type = (S_ISDIR(fileStat.st_mode)) ? DIRECTORY : NORMAL_FILE;
        fileinfoPtr->size = fileStat.st_size;

        if (ret.filedirs.size > 0)
        {
            fileinfoArray = (fileinfo_t *)realloc(fileinfoArray, ((ret.filedirs.size + 1) * sizeof(fileinfo_t)));
        }
        memcpy(fileinfoArray + ret.filedirs.size, fileinfoPtr, sizeof(*fileinfoPtr));
        ret.filedirs.size++;
    }

    // 如果查找到记录条数为0，那么需要提前回收空间，因为提前预分配了空间
    if (ret.filedirs.size == 0)
    {
        FREE_AND_NULLIFY(fileinfoArray);
    }

    ret.exec_status = true;
    sprintf(ret.description, "ls命令执行成功, 当前目录下一共有%lu个文件和子目录.", ret.filedirs.size);
    ret.filedirs.files = fileinfoArray;

    closedir(dp);

    return ret;
}

void lsCmdHandle(splictDataCarrier_st *splictDataCarrier)
{
    // // lsReturn_t ret = lsCmdSimulation(yypcurPath, path);
    // lsReturn_t ret = lsCmdSimulation(splictDataCarrier);
    // // send();
    // printf("lsCmdHandle开始send---------->\n");
    // send(splictDataCarrier->socketFd, &ret, sizeof(ret), 0);

    // // 发送文件信息
    // for (size_t i = 0; i < ret.filedirs.size; i++)
    // {
    //     fileinfo_t fileinfo = ret.filedirs.files[i];
    //     send(splictDataCarrier->socketFd, &fileinfo, sizeof(fileinfo), 0);
    // }

    // printf("lsCmdHandle结束send---------->\n");
    char absPath[256] = {0};
    getServerAbsPath(splictDataCarrier, absPath);
    DIR *dirp = opendir(absPath);
    // 打开目录流需要进行错误处理
    if (dirp == NULL)
        return;
    // printf("/////////////266\n");
    char sendBuf[1024] = {0};
    struct dirent *pdirent;
    // 循环读目录项并打印目录信息，循环结束的条件是返回值为NULL
    while ((pdirent = readdir(dirp)) != NULL)
    {

        if (memcmp(pdirent->d_name, ".", 1) == 0 || memcmp(pdirent->d_name, "..", 2) == 0)
            continue;
        strcat(sendBuf, pdirent->d_name);
        strcat(sendBuf, "&");
    }
    sendBuf[strlen(sendBuf)] = '\0';
    int dataLen = strlen(sendBuf);
    if (dataLen == 0)
    {
        // 说明目录为空
        send(splictDataCarrier->socketFd, &dataLen, 4, 0);
        closedir(dirp);
        return;
    }

    send(splictDataCarrier->socketFd, &dataLen, 4, 0);
    send(splictDataCarrier->socketFd, &sendBuf, dataLen, 0);
    // 及时释放资源，关闭目录流
    closedir(dirp);
}

// puts命令处理,上传文件
void putsFunc(char **tokens, char *absPath, char *cur, int net_fd, int len) // 旭
{
    int Flag; // Flag=0路径格式错误，Flag=1没传完，Flag=2已经传完，Flag=3还没有上传

    // 判断命令格式是否正确
    if (len <= 1 || strcmp(tokens[0], "puts") != 0)
    {
        // 命令结果标志位，如果结果为0，cd处理命令错误，不需要修改客户端当前工作路径
        // 结果为1正确，需要修改客户端当前工作路径
        Flag = 0;
        int ret = send(net_fd, &Flag, sizeof(int), MSG_NOSIGNAL);
        ERROR_CHECK(ret, -1, "send");
        return;
    }

    // 获得当前客户端绝对路径
    char path[1024] = {0};
    memset(path, 0, sizeof(path));
    strcpy(path, absPath);

    // 获取文件名长度和文件名
    char file_name[50] = {0};
    memset(file_name, 0, sizeof(file_name));
    int len1 = 0;
    int ret = recv(net_fd, &len1, sizeof(int), MSG_WAITALL);
    ERROR_CHECK(ret, -1, "recv");
    ret = recv(net_fd, file_name, len1, MSG_WAITALL);
    ERROR_CHECK(ret, -1, "recv");

    // 读取文件长度
    off_t file_size = 0;
    ret = recv(net_fd, &file_size, sizeof(off_t), MSG_WAITALL);
    ERROR_CHECK(ret, -1, "recv");

    // 判断上传路径是否有文件
    if (isExist(cur, file_name) == true)
    {
        int file_fd = open(path, O_RDWR);
        off_t curSize = lseek(file_fd, 0, SEEK_END);
        // printf("cursize:%jd\n", curSize);
        // printf("file_size:%jd\n", file_size);
        if (file_size > curSize)
        {
            // printf("当前文件已经存在，但没有传完\n");
            Flag = 1;
            ret = send(net_fd, &Flag, sizeof(int), 0);
            ERROR_CHECK(ret, -1, "send");
            ret = send(net_fd, &curSize, sizeof(off_t), 0);
            ERROR_CHECK(ret, -1, "send");
            int count = 0;
            char buf[1024] = {0};
            memset(buf, 0, sizeof(buf));
            while ((count = read(net_fd, buf, sizeof(buf))) > 0)
            {
                ret = write(file_fd, buf, count);
                if (ret <= 0)
                {
                    break;
                }
                memset(buf, 0, sizeof(buf));
            }
            // ftruncate(file_fd, file_size - curSize);
            // char *p = (char *)mmap(NULL, file_size - curSize, PROT_READ | PROT_WRITE, MAP_SHARED, file_fd, curSize);
            // ERROR_CHECK(p, MAP_FAILED, "mmap");
            // recv(net_fd, p, file_size - curSize, MSG_WAITALL);
            // munmap(p, file_size - curSize);
            close(file_fd);
            return;
        }
        else // 当前文件已经存在而且传完
        {
            Flag = 2;
            // printf("当前文件已经存在而且传完\n");
            ret = send(net_fd, &Flag, sizeof(int), 0);
            ERROR_CHECK(ret, -1, "send");
            return;
        }
    }

    // 没有上传，利用mmap上传
    Flag = 3;
    // printf("完全没有上传\n");
    ret = send(net_fd, &Flag, sizeof(int), 0);
    ERROR_CHECK(ret, -1, "send");

    // 利用mmap上传文件,而且文件没有上传
    printf("path:%s\n", path);
    int file_fd = open(path, O_RDWR | O_CREAT, 0666);
    ftruncate(file_fd, file_size);
    char *p = (char *)mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, file_fd, 0);
    ERROR_CHECK(p, MAP_FAILED, "mmap");
    recv(net_fd, p, file_size, MSG_WAITALL);
    munmap(p, file_size);
    close(file_fd);
    return;
}

// gets命令处理,下载文件
void sHandleGets(splictDataCarrier_st *splictDataCarrier)
{
    int ret;
    // 程序执行状态, 用来给客户端返回信息
    char sendStatusMsg[1024] = {0};
    int status = 0; // 状态  1: 文件不存在   5: 本地已有文件不需要下载    7:本地文件大小大于服务端文件大小, 截断本地文件
    off_t noUse = 0;

    // 相对路径拼接成绝对路径
    char path[1024] = {0};
    strcpy(path, splictDataCarrier->serverPath);
    strcat(path, "/");
    strcat(path, splictDataCarrier->username);
    strcat(path, splictDataCarrier->virtual_path);
    // printf("path = %s\n", path);

    // 处理客户端发来的文件信息
    char fileName[256] = {0};
    off_t fileOffset = 0;
    sscanf(splictDataCarrier->additional, "%[^&]&%ld", fileName, &fileOffset);
    // printf("拿到文件名：%s\n", fileName);
    // printf("拿到对方已有的文件大小：%ld\n", fileOffset);

    // 对比文件大小，获得偏移量
    DIR *dp = opendir(path);
    if (dp == NULL)
    { // 目录不存在
        status = 1;
        sprintf(sendStatusMsg, "%d&%ld", status, noUse);
        ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
        if (ret == -1)
        {
            perror("send");
        }
        return;
    }

    // 目录存在，遍历目录
    struct dirent *dt;
    int fileExistFlag = 0;
    while ((dt = readdir(dp)) != NULL)
    {
        if (strcmp(dt->d_name, fileName) == 0)
        {
            fileExistFlag = 1;
            // printf("///////////////////162///////////找到文件\n");
            break;
        }
    }
    closedir(dp);
    if (fileExistFlag == 0)
    { // 文件不存在
        status = 2;
        sprintf(sendStatusMsg, "%d&%ld", status, noUse);
        ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
        if (ret == -1)
        {
            perror("send");
        }
        return;
    }

    // 到这里说明文件存在，则打开该文件
    char openFile[512];
    strcpy(openFile, path);
    // strcat(openFile, "/");
    strcat(openFile, fileName);
    // printf("openFile: %s\n", openFile);
    int srcFd = open(openFile, O_RDWR);
    if (srcFd == -1)
    { // 打开文件失败
        status = 3;
        sprintf(sendStatusMsg, "%d&%ld", status, noUse);
        ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
        if (ret == -1)
        {
            perror("send");
        }
        return;
    }

    // 获得文件状态
    struct stat st;
    fstat(srcFd, &st);
    // 把文件大小返回给客户端
    off_t requestFileSize = st.st_size; // 服务端文件的实际大小
    if (requestFileSize == fileOffset)
    {
        printf("status = 5\n");
        status = 5;
        sprintf(sendStatusMsg, "%d&%ld", status, noUse);
        ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
        if (ret == -1)
        {
            close(srcFd);
            perror("send");
        }
    }
    else if (requestFileSize < fileOffset) // 如果超出，则截断，并指定给客户端文件大小
    {
        printf("status = 7\n");
        status = 7;
        sprintf(sendStatusMsg, "%d&%ld", status, requestFileSize);
        ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
        if (ret == -1)
        {
            close(srcFd);
            perror("send");
        }
    }
    else
    { // 运行到这里的条件是： requestFileSize > fileOffset, 即请求服务器端的文件大小大于本地文件大小, 到这里说明需要传文件

        status = 8;
        sprintf(sendStatusMsg, "%d&%ld", status, requestFileSize);
        ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
        if (ret == -1)
        {
            close(srcFd);
            perror("send");
            return;
        }

        // 传文件
        // printf("起始映射：%ld, 文件大小: %ld\n", fileOffset, requestFileSize);
        ssize_t toSend = requestFileSize - fileOffset; // 还要发送的文件大小

        ssize_t sent = sendfile(splictDataCarrier->socketFd, srcFd, &fileOffset, toSend);
        if (sent == -1)
        {
            perror("sendfile");
        }

        // while (toSend > 0)
        // {
        //     ssize_t sent = sendfile(splictDataCarrier->socketFd, srcFd, &fileOffset, toSend);
        //     if (sent == -1)
        //     {
        //         perror("sendfile");
        //         break;
        //     }
        //     toSend -= sent;
        // }
    }

    close(srcFd);
    return;
}
// gets命令处理,下载文件
// void sHandleGets(splictDataCarrier_st *splictDataCarrier)
// {
//     int ret;
//     // 程序执行状态, 用来给客户端返回信息
//     char sendStatusMsg[1024] = {0};
//     int status = 0; // 状态  1: 文件不存在   5: 本地已有文件不需要下载    7:本地文件大小大于服务端文件大小, 截断本地文件
//     off_t noUse = 0;

//     // 相对路径拼接成绝对路径
//     char path[1024] = {0};
//     strcpy(path, splictDataCarrier->serverPath);
//     strcat(path, "/");
//     strcat(path, splictDataCarrier->username);
//     strcat(path, splictDataCarrier->virtual_path);
//     // printf("path = %s\n", path);

//     // 处理客户端发来的文件信息
//     char fileName[256] = {0};
//     off_t fileOffset = 0;
//     sscanf(splictDataCarrier->additional, "%[^&]&%ld", fileName, &fileOffset);
//     // printf("文件名：%s\n", fileName);
//     // printf("对方已有的文件大小：%ld\n", fileOffset);

//     // 对比文件大小，获得偏移量
//     DIR *dp = opendir(path);
//     if (dp == NULL)
//     { // 目录不存在
//         status = 1;
//         sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//         ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//         if (ret == -1)
//         {
//             perror("send");
//         }
//         return;
//     }

//     // 目录存在，遍历目录
//     struct dirent *dt;
//     int fileExistFlag = 0;
//     while ((dt = readdir(dp)) != NULL)
//     {
//         if (strcmp(dt->d_name, fileName) == 0)
//         {
//             fileExistFlag = 1;
//             // printf("///////////////////162///////////找到文件\n");
//             break;
//         }
//     }
//     closedir(dp);
//     if (fileExistFlag == 0)
//     { // 文件不存在
//         status = 2;
//         sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//         ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//         if (ret == -1)
//         {
//             perror("send");
//         }
//         return;
//     }

//     // 到这里说明文件存在，则打开该文件
//     char openFile[512];
//     strcpy(openFile, path);
//     strcat(openFile, fileName);
//     // printf("openFile: %s\n", openFile);
//     int srcFd = open(openFile, O_RDWR);
//     if (srcFd == -1)
//     { // 打开文件失败
//         status = 3;
//         sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//         ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//         if (ret == -1)
//         {
//             perror("send");
//         }
//         return;
//     }

//     // 获得文件状态
//     struct stat st;
//     fstat(srcFd, &st);
//     // 把文件大小返回给客户端
//     off_t requestFileSize = st.st_size; // 服务端文件的实际大小
//     if (requestFileSize == fileOffset)
//     {
//         status = 5;
//         sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//         ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//         if (ret == -1)
//         {
//             close(srcFd);
//             perror("send");
//         }
//     }
//     else if (requestFileSize < fileOffset) // 如果超出，则截断，并指定给客户端文件大小
//     {
//         status = 7;
//         sprintf(sendStatusMsg, "%d&%ld", status, requestFileSize);
//         ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//         if (ret == -1)
//         {
//             close(srcFd);
//             perror("send");
//         }
//     }
//     else
//     { // 运行到这里的条件是： requestFileSize > fileOffset, 即请求服务器端的文件大小大于本地文件大小, 到这里说明需要传文件

//         // // 为配合mmap使用，判断客户端已有的文件大小是不是4096字节的倍数，不是的话就计算返回4096倍数，余数字节切掉
//         if ((fileOffset % 4096) != 0)
//         {
//             // printf("fileOffset = %ld\n", fileOffset);
//             fileOffset = fileOffset / 4096 * 4096;
//             // printf("fileOffset = %ld\n", fileOffset);
//         }
//         status = 8;
//         sprintf(sendStatusMsg, "%d&%ld", status, requestFileSize);
//         ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//         if (ret == -1)
//         {
//             close(srcFd);
//             perror("send");
//             return;
//         }
//         // printf("while before\n");

//         // // 传文件
//         // ssize_t toSend = requestFileSize - fileOffset; // 还要发送的文件大小
//         // while (toSend > 0)
//         // {
//         //     ssize_t sent = sendfile(splictDataCarrier->socketFd, srcFd, &fileOffset, toSend);
//         //     if (sent == -1)
//         //     {
//         //         perror("sendfile");
//         //         close(srcFd);
//         //         return;
//         //     }
//         //     toSend -= sent;
//         // }

//         // mmap方式发送文件：
//         while (1)
//         {
//             // 确定本次复制的字节大小
//             // 如果已复制字节数加上一次复制的块大小超过了源文件大小，说明这是最后一次映射复制，此时只需要映射剩余文件内容就可以了
//             // 不是最后一次映射复制，那就继续映射一整个块的大小
//             off_t curBlockSize = (requestFileSize - fileOffset < BLOCK_SIZE) ? (requestFileSize - fileOffset) : BLOCK_SIZE;
//             // printf("fileOffset = %ld  curBlockSize= %ld\n", fileOffset, curBlockSize);
//             // 映射目标文件
//             char *srcp =
//                 (char *)mmap(NULL, curBlockSize, PROT_READ | PROT_WRITE, MAP_SHARED, srcFd, fileOffset);
//             if (srcp == (void *)-1)
//             {
//                 close(srcFd);
//                 perror("mmap");
//                 return;
//             }

//             // char buf[BLOCK_SIZE] = {0};
//             // int count = read(srcFd, buf, curBlockSize);
//             // if (count <= 0)
//             // {
//             //     munmap(srcp, curBlockSize);
//             //     break;
//             // }
//             ret = send(splictDataCarrier->socketFd, srcp, curBlockSize, 0);
//             if (ret == -1)
//             { // 对端已关闭
//                 munmap(srcp, curBlockSize);
//                 break;
//             }
//             // 解除映射
//             munmap(srcp, curBlockSize);
//             // 更新已复制的字节数
//             fileOffset += curBlockSize;

//             if (fileOffset >= requestFileSize)
//             {
//                 break;
//             }
//         }
//     }
//     // printf("while end\n");

//     close(srcFd);
//     return;
// }
// // gets命令处理,下载文件
// // void sHandleGets(splictDataCarrier_st *splictDataCarrier)
// // {
// //     // 判断文件是否存在
// //     char absPath[256] = {0};
// //     bool ret = getServerAbsPath(splictDataCarrier, absPath);
// //     long serverFileSize;
// //     if (ret == false)
// //     {
// //         // 文件不存在，返回0
// //         serverFileSize = 0;
// //         send(splictDataCarrier->socketFd, &serverFileSize, sizeof(long), 0);
// //         return;
// //     }
// //     else
// //     {
// //         // 文件存在，返回文件大小
// //         // 获取文件大小
// //         struct stat pstat;
// //         stat(absPath, &pstat);
// //         printf("文件大小:%ld\n", pstat.st_size);
// //         serverFileSize = pstat.st_size;
// //         send(splictDataCarrier->socketFd, &serverFileSize, sizeof(long), 0);
// //     }

//     // 发送文件的路径，让客户端
//     // 等待客户端回应【考虑断点续传，如果客户端有部分文件，那只需要发送剩下部分即可】
//     long clientFileSize;
//     int count = recv(splictDataCarrier->socketFd, &clientFileSize, sizeof(long), MSG_WAITALL);
//     if (count == 0)
//     {
//         printf("对端关闭...\n");
//         return;
//     }
    
//     int fileFd = open(absPath, O_RDONLY);

//     // sendfile(splictDataCarrier->socketFd,fileFd,&offset,serverFileSize);
//     int sockFd = splictDataCarrier->socketFd;
//     char sendBuf[1024 * 16];
//     long totalFileSize = serverFileSize; // 总文件大小
//     long offset = clientFileSize; // 偏移量
//     lseek(fileFd,offset,SEEK_SET);
    
//     long alreadSendFileSize = 0;
//     long remainFileSize = totalFileSize - offset; // 需要传递的大小
//     while (1)
//     {
//         printf("remainFileSize:%ld\n", remainFileSize);
//         if (remainFileSize == 0)
//         {
//             printf("传输完毕...\n");
//             break;
//         }
//         int count;
//         if (remainFileSize >= sizeof(sendBuf))
//         {
//             read(fileFd,sendBuf,sizeof(sendBuf));
//             count = send(sockFd, sendBuf, sizeof(sendBuf), MSG_WAITALL);
//             if(count != sizeof(sendBuf)) return;
//         }
//         else
//         {
//             read(fileFd,sendBuf,remainFileSize);
//             count = send(sockFd, sendBuf, remainFileSize, MSG_WAITALL);
//             if(count != remainFileSize) return;
//         }
//         send(sockFd,sendBuf,count,MSG_NOSIGNAL);
//         alreadSendFileSize += count;
//         remainFileSize = totalFileSize - alreadSendFileSize;
//         printf("offect:%ld",offset);
//     }
//     close(fileFd);

//     // int ret;
//     // // 程序执行状态, 用来给客户端返回信息
//     // char sendStatusMsg[1024] = {0};
//     // int status = 0; // 状态  1: 文件不存在   5: 本地已有文件不需要下载    7:本地文件大小大于服务端文件大小, 截断本地文件
//     // off_t noUse = 0;

//     // // 相对路径拼接成绝对路径
//     // char path[1024] = {0};
//     // strcpy(path, splictDataCarrier->serverPath);
//     // strcat(path, "/");
//     // strcat(path, splictDataCarrier->username);
//     // strcat(path, splictDataCarrier->virtual_path);
//     // // printf("path = %s\n", path);

//     // // 处理客户端发来的文件信息
//     // char fileName[256] = {0};
//     // off_t fileOffset = 0;
//     // sscanf(splictDataCarrier->additional, "%[^&]&%ld", fileName, &fileOffset);
//     // // printf("文件名：%s\n", fileName);
//     // // printf("对方已有的文件大小：%ld\n", fileOffset);

//     // // 对比文件大小，获得偏移量
//     // DIR *dp = opendir(path);
//     // if (dp == NULL)
//     // { // 目录不存在
//     //     status = 1;
//     //     sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//     //     ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//     //     if (ret == -1)
//     //     {
//     //         perror("send");
//     //     }
//     //     return;
//     // }

//     // // 目录存在，遍历目录
//     // struct dirent *dt;
//     // int fileExistFlag = 0;
//     // while ((dt = readdir(dp)) != NULL)
//     // {
//     //     if (strcmp(dt->d_name, fileName) == 0)
//     //     {
//     //         fileExistFlag = 1;
//     //         // printf("///////////////////162///////////找到文件\n");
//     //         break;
//     //     }
//     // }
//     // closedir(dp);
//     // if (fileExistFlag == 0)
//     // { // 文件不存在
//     //     status = 2;
//     //     sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//     //     ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//     //     if (ret == -1)
//     //     {
//     //         perror("send");
//     //     }
//     //     return;
//     // }

//     // // 到这里说明文件存在，则打开该文件
//     // char openFile[512];
//     // strcpy(openFile, path);
//     // strcat(openFile, fileName);
//     // // printf("openFile: %s\n", openFile);
//     // int srcFd = open(openFile, O_RDWR);
//     // if (srcFd == -1)
//     // { // 打开文件失败
//     //     status = 3;
//     //     sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//     //     ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//     //     if (ret == -1)
//     //     {
//     //         perror("send");
//     //     }
//     //     return;
//     // }

//     // // 获得文件状态
//     // struct stat st;
//     // fstat(srcFd, &st);
//     // // 把文件大小返回给客户端
//     // off_t requestFileSize = st.st_size; // 服务端文件的实际大小
//     // if (requestFileSize == fileOffset)
//     // {
//     //     status = 5;
//     //     sprintf(sendStatusMsg, "%d&%ld", status, noUse);
//     //     ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//     //     if (ret == -1)
//     //     {
//     //         close(srcFd);
//     //         perror("send");
//     //     }
//     // }
//     // else if (requestFileSize < fileOffset) // 如果超出，则截断，并指定给客户端文件大小
//     // {
//     //     status = 7;
//     //     sprintf(sendStatusMsg, "%d&%ld", status, requestFileSize);
//     //     ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//     //     if (ret == -1)
//     //     {
//     //         close(srcFd);
//     //         perror("send");
//     //     }
//     // }
//     // else
//     // { // 运行到这里的条件是： requestFileSize > fileOffset, 即请求服务器端的文件大小大于本地文件大小, 到这里说明需要传文件

//     //     // // 为配合mmap使用，判断客户端已有的文件大小是不是4096字节的倍数，不是的话就计算返回4096倍数，余数字节切掉
//     //     // if ((fileOffset % 4096) != 0)
//     //     // {
//     //     //     // printf("fileOffset = %ld\n", fileOffset);
//     //     //     fileOffset = fileOffset / 4096 * 4096;
//     //     //     // printf("fileOffset = %ld\n", fileOffset);
//     //     // }
//     //     status = 8;
//     //     sprintf(sendStatusMsg, "%d&%ld", status, requestFileSize);
//     //     ret = send(splictDataCarrier->socketFd, sendStatusMsg, sizeof(sendStatusMsg), MSG_NOSIGNAL);
//     //     if (ret == -1)
//     //     {
//     //         close(srcFd);
//     //         perror("send");
//     //         return;
//     //     }
//     //     // printf("while before\n");
//     //     // 传文件
//     //     // printf("起始映射：%ld, 文件大小: %ld\n", fileOffset, requestFileSize);
//     //     ssize_t toSend = requestFileSize - fileOffset; // 还要发送的文件大小
//     //     while (toSend > 0)
//     //     {
//     //         ssize_t sent = sendfile(splictDataCarrier->socketFd, srcFd, &fileOffset, toSend);
//     //         if (sent == -1)
//     //         {
//     //             perror("sendfile");
//     //             close(srcFd);
//     //             return;
//     //         }
//     //         toSend -= sent;
//     //     }
//     // }
//     // // printf("while end\n");

//     // close(srcFd);
//     // return;
// }


// remove命令处理
int removeFunc(splictDataCarrier_st *splictDataCarrier) // 飞 -> 唐
{
    // 字符串拆分【客户端传来的命令】
    char command[255] = {0};
    memcpy(command, splictDataCarrier->command, strlen(splictDataCarrier->command));

    // 得到命令
    char *cmd = strtok(command, " "); // 通过空格拆分字符串
    trimString(cmd);                  // 去除前后空格

    // 获得第二个参数
    strtok(NULL, " ");

    // 得到路径并判断路径是否合法，并得到绝对路径
    char serverAbsPath[255] = {0};
    bool flag = getServerAbsPath(splictDataCarrier, serverAbsPath);
    int alreadyRead = 0;      // 定义拼接字符数组时的偏移量
    char sendBuf[1024] = {0}; // 定义发送的数据载体
    if (flag == false)
    {
        // 没有找到该文件
        // 拼接命令返回状态
        printf("//////////////////////199//////////////////\n");
        int status = 0; // 表示返回成功
        memcpy(sendBuf + alreadyRead, &status, 4);
        alreadyRead += 4;
    }
    else
    {
        // 找到了该文件
        int status = 1; // 表示返回成功
        memcpy(sendBuf + alreadyRead, &status, 4);
        alreadyRead += 4;
        status = remove(serverAbsPath);
    }
    send(splictDataCarrier->socketFd, sendBuf, sizeof(sendBuf), 0);
    printf("发送成功...\n");
    return 1;
}

// mkdir命令处理
void mkdirFunc(char **tokens, char *cur, int net_fd, int len) // 旭
{
    // 判断命令格式是否正确
    if (len <= 1 || strcmp(tokens[0], "mkdir") != 0)
    {
        // 命令结果标志位，如果结果为0，cd处理命令错误，不需要修改客户端当前工作路径
        // 结果为1正确，需要修改客户端当前工作路径
        int flag = 0;
        int ret = send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
        ERROR_CHECK(ret, -1, "send");
        return;
    }
    // 当前服务器端的初始绝对路径
    char path[1024] = {0};
    memset(path, 0, sizeof(path));
    strcpy(path, cur);
    // printf("path:%s\n", path);
    // 创建多级目录
    if (strcmp(tokens[1], "-p") == 0)
    {
        int num = 2, flag = 0;
        if (isExist(path, tokens[num]) == false)
        {

            while (num < len)
            {
                strcat(path, "/");
                strcat(path, tokens[num]);
                mkdir(path, 0775);
                num++;
            }
            flag = 1;
            send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
            return;
        }
        // 命令结果标志位，如果结果为0，cd处理命令错误，不需要修改客户端当前工作路径
        // 结果为1正确，需要修改客户端当前工作路径
        flag = 0;
        int ret = send(net_fd, &flag, sizeof(int), MSG_NOSIGNAL);
        ERROR_CHECK(ret, -1, "send");
        return;
    }

    int num = 1;
    // 同一个目录下创建多个文件夹
    if (len >= 3)
    {
        // 判断当前目录下是否有这些文件夹
        while (num < len)
        {
            bool flag = isExist(path, tokens[num]);
            if (flag == true)
            {

                int x = 0;
                int ret = send(net_fd, &x, sizeof(int), 0);
                ERROR_CHECK(ret, -1, "send");
                return;
            }
            num++;
        }

        // 不存在这些文件夹，开始创建
        num = 1;
        while (num < len)
        {
            memset(path, 0, sizeof(path));
            strcpy(path, cur);
            strcat(path, "/");
            strcat(path, tokens[num]);
            mkdir(path, 0775);
            num++;
        }
        int x = 1;
        int ret = send(net_fd, &x, sizeof(int), 0);
        ERROR_CHECK(ret, -1, "send");
        return;
    }

    // 只创建一个文件夹
    int flag;
    num = 1;
    while (num < len)
    {
        flag = 0;
        if (isExist(path, tokens[num]) == true)
        {
            if (num != len - 1)
            {
                flag = 0;
            }
            else
            {
                flag = 1;
            }
        }

        // 创建的文件夹已经存在或者路径不正确
        if (flag == 1)
        {
            int x = 0;
            int ret = send(net_fd, &x, sizeof(int), 0);
            ERROR_CHECK(ret, -1, "send");
            return;
        }

        // 此次循环判断如果文件夹存在，修改服务器路径，修改服务器端的路径
        strcat(path, "/");
        strcat(path, tokens[num]);
        if (num == len - 1)
        {
            mkdir(path, 0775);
        }
        num++;
    }
    // 创建文件夹不需要修改客户端当前工作路径
    // mkdir命令正确，填写返回值信息
    int x = 1;
    int ret = send(net_fd, &x, sizeof(int), 0);
    ERROR_CHECK(ret, -1, "send");
    return;
}

// 无效命令响应
serv2clientMsg_t invalidFunc(char **tokens) // 飞
{
    serv2clientMsg_t msg;
    memset(&msg, 0, sizeof(msg));
    return msg;
}

CMD_TYPE getCommandType(const char *command, char *cmdType)
{
    char *delimiters = " \n\t";
    int size = 0;

    char **tokens = splitString(command, delimiters, &size);
    CMD_TYPE type;
    if (tokens == NULL || !isValidCmd(tokens[0], &type))
    {
        // 分割命令失败或是不支持的命令类型，返回INVALID_CMD
        strcpy(cmdType, "uknow type");
    }
    else
    {
        // TODO: 如何释放splintString中动态分配的内存，并且不造成cmdType访问野指针？
        // 已经解决通过使用strcpy或memcopy函数将字符串复制到传入传出参数中
        strcpy(cmdType, tokens[0]);
    }

    freeTokens(&tokens, size); // 释放动态分配内存
    return type;
}

static bool isValidCmd(const char *cmd, CMD_TYPE *type)
{
    // TODO: 从配置文件中读取支持的命令列表
    char *supportCmds[] = {
        "cd",
        "ls",
        "pwd",
        "gets",
        "puts",
        "remove",
        "rm",
        "mkdir",
    };

    size_t len = COUNT_OF(supportCmds);

    // TODO: 当前枚举值定义为硬编码需要修改为按照从配置文件中读取顺序定义
    for (size_t i = 0; i < len; i++)
    {
        if (strcmp(cmd, supportCmds[i]) == 0)
        {
            *type = (CMD_TYPE)i;
            return true;
        }
    }

    *type = INVALID_CMD;
    return false;
}

/*
 * 单元测试函数实现，测试完成后需要删除
 * 创建人：曾爽
 * 创建事件：2024/07/06
 * */

void unitest_lsCmdSimulation(splictDataCarrier_st *splictDataCarrier)
{
    // char *curPath = "/home/tsang/srcode/group_project";
    // char *path = "client";
    // char *path = "/home/tsang/";
    lsReturn_t ret = lsCmdSimulation(splictDataCarrier);

    if (true == ret.exec_status)
    {
        // printf("Desrciption: %s\n", ret.description);
        // printf("Total files: %lu\n", ret.filedirs.size);
        // size_t totalSize = ret.filedirs.size;
        // fileinfo_t *fileinfoArray = ret.filedirs.files;

        // for (size_t i = 0; i < totalSize; i++)
        // {
        //     fileinfo_t fileinfo = fileinfoArray[i];
        //     // printf("File name: %s\n", fileinfo.file_name);
        //     // printf("File size: %lu\n", fileinfo.size);
        //     // printf("File type: %d\n", fileinfo.file_type);
        //     printf("\n");
        // }
    }
    else
    {
        // printf("Desrciption: %s\n", ret.description);
        // printf("执行失败\n");
    }
    // 释放lsCmdSimulation中动态分配的内存
    // freeArrayOfPtrs();
    // printf("测试unitest_lsCmdSimulation结束\n");
}
